#include "FreeRTOS_Task.h"

/* START_TASK */
#define START_TASK_PRIO 	2			// 任务优先级
#define START_STK_SIZE  	128			// 任务堆栈大小
void start_task(void *pvParameters);	// 任务函数
TaskHandle_t StartTask_Handler;  		// 任务句柄

/* Led_Flash */
#define Led_Flash_PRIO 		2			// 任务优先级
#define Led_Flash_STK_SIZE  128			// 任务堆栈大小
void Led_Flash(void *pvParameters);		// 任务函数
TaskHandle_t Led_Flash_Handler;  		// 任务句柄

/* Key_Scan */
#define Key_Scan_PRIO 		2			// 任务优先级
#define Key_Scan_STK_SIZE  	128			// 任务堆栈大小
void Key_Scan(void *pvParameters);		// 任务函数
TaskHandle_t Key_Scan_Handler;  		// 任务句柄

/* Key_Task */
#define Key_Task_PRIO 		2			// 任务优先级
#define Key_Task_STK_SIZE  	128			// 任务堆栈大小
void Key_Task(void *pvParameters);		// 任务函数
TaskHandle_t Key_Task_Handler;  		// 任务句柄

typedef struct {
	uint8_t key_num;
	uint8_t key_stat;
} Key_Transmit_Type;

typedef struct {
	uint16_t key_times;
	uint8_t  key_old;
	uint8_t  key_num;
} Key_Type;

//Key_Type key;
//Key_Transmit_Type key_trans;
//Key_Transmit_Type key_val;

QueueHandle_t key_trans_queue;	// 用于把处理完的按键信号传给业务函数
QueueHandle_t key_queue;		// 用于存放检测到的按键状态

void FreeRTOS_Startup(void)
{
	xTaskCreate((TaskFunction_t	)start_task,			// 任务函数
				(const char*	)"start_task",			// 任务名称
				(uint16_t		)START_STK_SIZE,		// 任务堆栈大小
				(void*			)NULL,					// 任务函数的传入参数
				(UBaseType_t	)START_TASK_PRIO,		// 任务优先级
				(TaskHandle_t*	)&StartTask_Handler);	// 任务句柄

	vTaskStartScheduler();
}

void start_task(void *pvParameters)
{
	taskENTER_CRITICAL();
				
	xTaskCreate((TaskFunction_t	)Key_Task,				// 任务函数
				(const char*	)"Key_Task",			// 任务名称
				(uint16_t		)Key_Task_STK_SIZE,		// 任务堆栈大小
				(void*			)NULL,					// 任务函数的传入参数
				(UBaseType_t	)Key_Task_PRIO,			// 任务优先级
				(TaskHandle_t*	)&Key_Task_Handler);	// 任务句柄		
	
	key_queue 		= xQueueCreate(	(UBaseType_t) 1,
									(UBaseType_t) sizeof(Key_Type) );
		
	key_trans_queue = xQueueCreate(	(UBaseType_t) 1,
									(UBaseType_t) sizeof(Key_Transmit_Type) );
				
	vTaskDelete(NULL);
	taskEXIT_CRITICAL();
}

void Led_Flash(void *pvParameters)
{
	while(1)
	{
		HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13);
		vTaskDelay(500);
	}
}

void Key_Task (void *pvParameters)
{
  typedef enum
  {
    IDLE_STATE,   			//空闲
    PRESS_DETECTED_STATE,  	//按键按下
    RELEASE_DETECTED_STATE, //按键释放
    SHORT_PRESS_STATE,     	//短按
    LONG_PRESS_STATE,     	//长按
    DOUBLE_PRESS_STATE,  	//双击
	LONG_PRESS_STATE_END 	//长按结束状态
  } ButtonState;

  uint16_t SHORT_CLICK_THRESHOLD = 400;  	// 这个是第一次松开时间和第二次按下时间的判断时长
  uint16_t LONG_PRESS_THRESHOLD = 1000;  	// 定义长按的时间阈值（以FreeRTOS时基为单位）
  uint16_t PRESS_Time = 100;             	// 判断毛刺时长
  uint16_t BUTTON_ERROR_Time = 1500;  		// 按键长久状态卡死阈值

  ButtonState buttonState = IDLE_STATE;		//按键状态
  TickType_t pressStartTime = 0; 			//记录按下时间
  TickType_t lastReleaseTime = 0;			//记录上一次释放时间
  TickType_t ReleaseTime = 0;

  while (1)
  {
    int keyStatus = HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0);  //检测按键
    TickType_t currentTime = xTaskGetTickCount();
    switch (buttonState)
    {
    case IDLE_STATE:
      if (keyStatus == 0)   //如果按键按下
      {
        buttonState = PRESS_DETECTED_STATE; //切换到按键按下状态
        pressStartTime = currentTime;       //记录按下时间
      }
      break;

    case PRESS_DETECTED_STATE:    //按键 按下状态
      if (keyStatus == 1)       //检测按键松开时间
      {
        ReleaseTime = currentTime;  //记录按键放松时间
        buttonState = RELEASE_DETECTED_STATE;    //如果按下后释放则进入这里
      }
      else if (currentTime - pressStartTime > LONG_PRESS_THRESHOLD) //判断按键长按的时长如果符合则跳转到这里。
      {
        buttonState = LONG_PRESS_STATE;
      }
			else if(currentTime - pressStartTime>BUTTON_ERROR_Time) //防止按键卡死
			{
			buttonState = IDLE_STATE;
			}
      break;
    case LONG_PRESS_STATE_END:    //长按结束后的状态跳转这里等待按键松开 防止一直处于长按状态   /
      if (keyStatus == 1)
      {
        buttonState = IDLE_STATE;
      }
      break;

    case RELEASE_DETECTED_STATE:    //按键释放过后的状态
      if ( (keyStatus == 0) && (currentTime - ReleaseTime < SHORT_CLICK_THRESHOLD))        //如果按键再次按下并且第二次时长是在500ms以内按下的
      {
        buttonState = DOUBLE_PRESS_STATE;
      }
      else if ( (ReleaseTime - pressStartTime > PRESS_Time) && (currentTime - ReleaseTime > SHORT_CLICK_THRESHOLD)) //判断按键按下时长防止毛刺 在判断当前是否在双击范围内
      {
        buttonState = SHORT_PRESS_STATE;
      }
      else if (currentTime - ReleaseTime > BUTTON_ERROR_Time) //按键出现无法判断情况回到初态
      {
        buttonState = IDLE_STATE;
      }
      break;

    case SHORT_PRESS_STATE:
//      printf("单击\r\n");
	debug_printf("单击\r\n");

		if(Led_Flash_Handler == NULL)
		{
			xTaskCreate((TaskFunction_t	)Led_Flash,	// 任务函数
			(const char*	)"Led_Flash",			// 任务名称
			(uint16_t		)Led_Flash_STK_SIZE,	// 任务堆栈大小
			(void*			)NULL,					// 任务函数的传入参数
			(UBaseType_t	)Led_Flash_PRIO,		// 任务优先级
			(TaskHandle_t*	)&Led_Flash_Handler);	// 任务句柄
		}
		else
		{
			vTaskDelete(Led_Flash_Handler);
			Led_Flash_Handler = NULL;
			HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_SET);
		}
      buttonState = LONG_PRESS_STATE_END;
      break;

    case LONG_PRESS_STATE:
      printf("长按\r\n");

      buttonState = LONG_PRESS_STATE_END;
      break;

    case DOUBLE_PRESS_STATE:
      buttonState = LONG_PRESS_STATE_END;
      printf("双击\r\n");
	
      break;
    }
    vTaskDelay (10);
  }
}



